#ifndef __WIZ_DATATYPE_TUPLE_CONS_HPP__SHANHAOBO_19800429__
#define __WIZ_DATATYPE_TUPLE_CONS_HPP__SHANHAOBO_19800429__

#include "../../Base/TypeTraits/WizBaseTypeTraits.hpp"

namespace Wiz
{
    namespace Tuple
    {
        namespace Cons
        {
            template<typename HeadT, typename TailT = ::Wiz::Null::Type>
            struct Type;

            template<typename HeadT, typename TailT>
            struct Builder
            {
            private:
                static const ::Wiz::Bool::Type NextIsNull = ::Wiz::Null::IsA<TailT>::Value;
            public:
                typedef ::Wiz::Tuple::Cons::Type<HeadT, TailT>  tReturn;
            };

#if 0
            template<>
            struct Builder<::Wiz::Null::Type, ::Wiz::Null::Type>
            {
                typedef ::Wiz::Null::Type                       tReturn;
            };
#endif

            // Map the N elements of a tuple into a cons list
            template<
                typename T0,
                typename T1 = ::Wiz::Null::Type,
                typename T2 = ::Wiz::Null::Type,
                typename T3 = ::Wiz::Null::Type,
                typename T4 = ::Wiz::Null::Type,
                typename T5 = ::Wiz::Null::Type,
                typename T6 = ::Wiz::Null::Type,
                typename T7 = ::Wiz::Null::Type,
                typename T8 = ::Wiz::Null::Type,
                typename T9 = ::Wiz::Null::Type
            >
            struct FromTuple
            {
                typedef typename ::Wiz::Tuple::Cons::Builder<T9, ::Wiz::Null::Type>::tReturn   tCons9;
                typedef typename ::Wiz::Tuple::Cons::Builder<T8, tCons9>::tReturn              tCons8;
                typedef typename ::Wiz::Tuple::Cons::Builder<T7, tCons8>::tReturn              tCons7;
                typedef typename ::Wiz::Tuple::Cons::Builder<T6, tCons7>::tReturn              tCons6;
                typedef typename ::Wiz::Tuple::Cons::Builder<T5, tCons6>::tReturn              tCons5;
                typedef typename ::Wiz::Tuple::Cons::Builder<T4, tCons5>::tReturn              tCons4;
                typedef typename ::Wiz::Tuple::Cons::Builder<T3, tCons4>::tReturn              tCons3;
                typedef typename ::Wiz::Tuple::Cons::Builder<T2, tCons3>::tReturn              tCons2;
                typedef typename ::Wiz::Tuple::Cons::Builder<T1, tCons2>::tReturn              tCons1;
                typedef typename ::Wiz::Tuple::Cons::Builder<T0, tCons1>::tReturn              tCons0;
            };
        } /// end of namespace Cons

        namespace Init
        {
            template <class MyTailT>
            struct Tail
            {
                template <class HeadT, class TailT>
                static typename ::Wiz::TypeTraits::Get::ReferenceConst<TailT>::tType
                    Execute(::Wiz::Tuple::Cons::Type<HeadT,TailT> const& u, long)
                {
                    return u.GetTail();
                }
            };

            template <>
            struct Tail<::Wiz::Null::Type>
            {
                template <class HeadT>
                static ::Wiz::Null::Type Execute(::Wiz::Tuple::Cons::Type<HeadT, ::Wiz::Null::Type> const&, long)
                {
                    return ::Wiz::Null::Type();
                }

                template <class U>
                static ::Wiz::Null::Type Execute(U const&, ...)
                {
                    return ::Wiz::Null::Type();
                }
            private:
                template <class HeadT, class TailT>
                ::Wiz::Void::Type Execute(::Wiz::Tuple::Cons::Type<HeadT, TailT> const&, ::Wiz::Int::Type);
            };

            template <class OtherT>
            OtherT const&
            Head(OtherT const& u, ...)
            {
                return u;
            }

            template <class HeadT, class TailT>
            typename ::Wiz::TypeTraits::Get::ReferenceConst<TailT>::tType
                Head(::Wiz::Tuple::Cons::Type<HeadT,TailT> const& u, ::Wiz::Int::Type)
            {
                return u.GetHead();
            }
        } /// end of namespace Init

        namespace Cons
        {
            template<typename HeadT, typename TailT>
            struct Type
            {
                typedef Type        tThis;
                typedef HeadT       tHead;
                typedef TailT       tTail;
            private:
                typedef typename ::Wiz::TypeTraits::Get::Reference<tHead>::tType         tHeadRef;
                typedef typename ::Wiz::TypeTraits::Get::Reference<tTail>::tType         tTailRef;
                typedef typename ::Wiz::TypeTraits::Get::ReferenceConst<tHead>::tType    tHeadRefConst;
                typedef typename ::Wiz::TypeTraits::Get::ReferenceConst<tTail>::tType    tTailRefConst;
            public:
                tHead m_Head;
                tTail m_Tail;

                tHeadRef GetHead()
                {
                    return m_Head;
                }
                tTailRef GetTail()
                {
                    return m_Tail;
                }

                tHeadRefConst GetHead() const
                {
                    return m_Head;
                }
                tTailRefConst GetTail() const
                {
                    return m_Tail;
                }

                Type() : m_Head(), m_Tail() {}

                template<typename TailT>
                Type(tHeadRefConst h, const TailT& t) : m_Head(h), m_Tail(t.m_Head, t.m_Tail)
                {
                }

                Type(tHeadRefConst h, const ::Wiz::Null::Type& t) : m_Head(h), m_Tail(t)
                {
                }

                template <class OtherT>
                Type(const OtherT& Other)
                    : m_Head(::Wiz::Tuple::Init::Head(Other, 0))
                    , m_Tail(::Wiz::Tuple::Init::Tail<TailT>::Execute(Other, 0L))
                {
                }

                template<typename OtherT>
                Type& operator=(const OtherT& Other)
                {
                    m_Head = Other.m_Head;
                    m_Tail = Other.m_Tail;
                    return *this;
                }
            }; /// end of namespace Cons
        }; /// end of namespace Cons
    } /// end of namespace Tuple
} /// end of namespace Wiz

#endif /*__WIZ_DATATYPE_TUPLE_CONS_HPP__SHANHAOBO_19800429__*/
